/**
 * 
 */
package cc.dogtailflower.framework.basedao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import cc.dogtailflower.framework.resultsetmapper.ResultSetMapper;

/**
 * @author cc
 *
 */
public class JdbcOperationImpl<T> implements JdbcOperation<T>{
	
	private static final boolean AUTO_COMMIT = true;
	
	private DataSource dataSource;
	
	public JdbcOperationImpl(){
		
	}
	
	public JdbcOperationImpl(DataSource dataSource){
		this.dataSource = dataSource;
	}

	@Override
	public int execute(String sql, Object[] params) throws SQLException {
		Connection conn = getConnection(false);
		PreparedStatement stmt = null;
		int result = -1;
		try{
			stmt = createPreparedStatement(conn,sql,params);
			result = stmt.executeUpdate();
			conn.commit();
		}catch(Exception e){
			conn.rollback();
			e.printStackTrace();
		}finally{
			free(stmt);
			free(conn);
		}
		return result;
	}

	@Override
	public int execute(String sql) throws SQLException {
		return execute(sql,new Object[]{});
	}

	@Override
	public List<T> queryForResultSet(String sql, Object[] params,ResultSetMapper<T> mapper) throws SQLException {
		Connection conn = getConnection();
		PreparedStatement stmt = null;
		ResultSet rs = null;
		List<T> list = null;
		try{
			stmt = createPreparedStatement(conn,sql,params);
			rs = createResultSet(stmt);
			
			list = new ArrayList<T>();
			list.addAll(mapper.resultSetToObject(rs,null));

		}catch(Exception e){
			e.printStackTrace();
		}finally{
			free(stmt);
			free(conn);
		}
		return list;
	}

	@Override
	public List<T> queryForResultSet(String sql,ResultSetMapper<T> mapper) throws SQLException {
		return queryForResultSet(sql,new Object[]{},mapper);
	}

	@Override
	public List<T> queryForBean(String sql, Object[] params, ResultSetMapper<T> mapper,Class<?> targetClass) throws SQLException {
		Connection conn = getConnection();
		PreparedStatement stmt = null;
		ResultSet rs = null;
		List<T> list = null;
		try{
			stmt = createPreparedStatement(conn,sql,params);
			rs = createResultSet(stmt);
			list = new ArrayList<T>();
			list.addAll(mapper.resultSetToObject(rs,targetClass));
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			free(rs);
			free(stmt);
			free(conn);
		}
		return list;
	}

	@Override
	public List<T> queryForBean(String sql, ResultSetMapper<T> mapper,Class<?> targetClass) throws SQLException {
		return queryForBean(sql,new Object[]{},mapper,targetClass);
	}

	@Override
	public int queryForInt(String sql, Object[] params) throws SQLException {
		Connection conn = getConnection();
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try{
			stmt = createPreparedStatement(conn,sql,params);
			rs = createResultSet(stmt);
			while(rs.next()){
				return rs.getInt(1); //第一列数据
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			free(rs);
			free(stmt);
			free(conn);
		}
		return 0;
	}

	@Override
	public int queryForInt(String sql) throws SQLException {
		return queryForInt(sql,new Object[]{});
	}

	@Override
	public void free(Connection x) {
		if(x != null){
			try{
				x.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
	}

	@Override
	public void free(Statement x) {
		if(x != null){
			try{
				x.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		
	}

	@Override
	public void free(PreparedStatement x) {
		if(x != null){
			try{
				x.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}		
	}

	@Override
	public void free(ResultSet x) {
		if(x != null){
			try{
				x.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}		
	}

	@Override
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	@Override
	public Connection getConnection() {
		return getConnection(AUTO_COMMIT);
	}

	@Override
	public Connection getConnection(boolean autoCommit) {
		try{
			Connection conn = dataSource.getConnection();
			if(!autoCommit){
				conn.setAutoCommit(autoCommit);
			}
			return conn;
		}catch(SQLException e){
			e.printStackTrace();
		}
		return null;
	}
	
	public PreparedStatement createPreparedStatement(Connection conn,String sql,Object[] params) throws SQLException{
		
		PreparedStatement stmt = conn.prepareStatement(sql);
		for(int i = 0;i < params.length ; i++){
			stmt.setObject(i+1, params[i]); //preparedStatement索引从1开始
		}
		return stmt;
	}
	
	public ResultSet createResultSet(PreparedStatement stmt) throws SQLException{
		
		return stmt.executeQuery();
	}

}
